/**
 * @file CartCommandImpl.java
 * Projet eCOM 2010 (Miage Descartes)
 * @author Doido Sébastien
 * @version 2
 * @brief Shell : Gestion des fonctionnalités relatives au panier
 */
package ecom.shell;

import ecom.beans.CartException;
import ecom.beans.CartLine;
import ecom.beans.EcomCustomerRemote;
import ecom.beans.ProductBean;
import ecom.beans.ProductStoreBean;
import ecom.beans.UnknownIdentifier;
import ecom.shell.OutputCommandImpl.Outputs;
import ecom.shell.ShellConstantes.RESULT_ACTION;
import java.io.PrintStream;
import java.text.DecimalFormat;
import java.util.StringTokenizer;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

public class CartCommandImpl implements ShellCommand {

    private ShellContext _context = null;

    public CartCommandImpl(ShellContext context) {
        _context = context;
    }

    /**
     * @brief Renvoie le nom de la commande
     * @return le nom de la commande
     */
    public String getName() {
        return "cart";
    }

    /**
     * @brief Renvoie la manière d'utiliser la commande
     * @return la manière d'utiliser la commande
     */
    public String getUsage() {
        return "cart";
    }

    /**
     * @brief Renvoie la description de la commande
     * @return la description de la commande
     */
    public String getShortDescription() {
        String description = "Cart Management\n";
        description += "\t  : [without arg].........................................products in cart\n";
        description += "\t  : -add .p [product ID] .s [store ID] .q [quantity]......add a specified quantity for product/store\n";
        description += "\t  : -remove .p [product ID] .s [store ID] .q [quantity]...remove a specified quantity for product/store\n";
        description += "\t  : -buy [account ID].....................................buy cart with a specified account\n";

        return description;
    }

    /**
     * @brief Exécute la commande
     * @param cmdline : commande à exécuter
     * @param out : flux d'affichage std
     * @param err : flux d'affichage err
     * @return les données à afficher
     * @throws java.lang.Exception : erreur durant l'exécution de la méthode
     */
    public String execute(String cmdline, PrintStream out, PrintStream err) {
        StringBuffer res = new StringBuffer();
        EcomCustomerRemote ecomCustomerBean = (EcomCustomerRemote) _context.getVar("customerBean");
        String currentCurrency = String.valueOf(_context.getVar("currency"));
        Outputs currentOutput = (Outputs) _context.getVar("output");

        StringTokenizer st = new StringTokenizer(cmdline, " ");

        // Ignore cmd
        st.nextToken();

        // without arg : list all products in cart
        if (st.countTokens() == 0) {
            return printCart(ecomCustomerBean, currentCurrency, out, currentOutput);
        } // With option
        else {
            String option = st.nextToken();
            try {
                // adding
                if (option.equals("-add")) {
                    // check args numbers
                    if (st.countTokens() == 6) {
                        if (".p".equalsIgnoreCase(st.nextToken().trim())) {
                            int productId = Integer.valueOf(st.nextToken().trim());
                            if (".s".equalsIgnoreCase(st.nextToken().trim())) {
                                int storeId = Integer.valueOf(st.nextToken().trim());
                                if (".q".equalsIgnoreCase(st.nextToken().trim())) {
                                    int q = Integer.valueOf(st.nextToken().trim());
                                    ecomCustomerBean.addProductToCart(productId, storeId, q);
                                    res.append(_context.returnCode("Product #" + productId + " added", RESULT_ACTION.SUCCESS));
                                }
                            }
                        }
                    } else {
                        err.println(Shell.INCORRECT_ARGS_NUMBER);
                    }
                } else if (option.equals("-remove")) {
                    // check args numbers
                    if (st.countTokens() == 6) {
                        if (".p".equalsIgnoreCase(st.nextToken().trim())) {
                            int productId = Integer.valueOf(st.nextToken().trim());
                            if (".s".equalsIgnoreCase(st.nextToken().trim())) {
                                int storeId = Integer.valueOf(st.nextToken().trim());
                                if (".q".equalsIgnoreCase(st.nextToken().trim())) {
                                    int q = Integer.valueOf(st.nextToken().trim());
                                    ecomCustomerBean.removeProductInCart(productId, storeId, q);
                                    res.append(_context.returnCode("Product #" + productId + " removed", RESULT_ACTION.SUCCESS));
                                }
                            }
                        }
                    } else {
                        err.println(Shell.INCORRECT_ARGS_NUMBER);
                    }
                } else if (option.equals("-buy")) {
                    int accountId = Integer.valueOf(st.nextToken().trim());
                    ecomCustomerBean.buyCart(accountId);
                    res.append(_context.returnCode("CART BOUGHT", RESULT_ACTION.SUCCESS));
                } else {
                    res.append(_context.returnCode(option + " is an unknown attribut !!", RESULT_ACTION.FAILED));
                    err.println("\t " + option + " is an unknown attribut !!");
                }
                return printCart(ecomCustomerBean, currentCurrency, out, currentOutput);
            } catch (UnknownIdentifier ex) {
                res.append(_context.returnCode(ex.toString(), RESULT_ACTION.FAILED));
                err.println(ex);
            } catch (CartException ex) {
                res.append(_context.returnCode(ex.toString(), RESULT_ACTION.FAILED));
                err.println("Error with Cart Management : " + ex);
            } catch (Exception ex) {
                res.append(_context.returnCode(ex.toString(), RESULT_ACTION.FAILED));
                err.println(ex);
            }
        }
        return res.toString();
    }

    /**
     * @brief Affichage du contenu du panier
     * @param ecomCustomerBean : bean remote client
     * @param currentCurrency : devise active
     * @param out : flux d'affichage std
     * @param currentOutput : sortie attendue
     * @return les données à afficher selon le type de sortie positionné
     */
    private String printCart(EcomCustomerRemote ecomCustomerBean, String currentCurrency, PrintStream out, Outputs currentOutput) {
        if (currentOutput.equals(Outputs.XML)) {
            return printCartXML(ecomCustomerBean, currentCurrency, out);
        } else if (currentOutput.equals(Outputs.TEXT)) {
            return printCartTEXT(ecomCustomerBean, currentCurrency, out);
        } else {
            return ("\t /!\\ Output format '" + currentOutput + "' is known but not implementing for this command");
        }

    }

    /**
     * @brief Affichage du contenu du panier (TEXT)
     * @param ecomCustomerBean : bean remote client
     * @param currentCurrency : devise active
     * @param out : flux d'affichage std
     * @return les données à afficher selon le type de sortie positionné
     */
    private String printCartTEXT(EcomCustomerRemote ecomCustomerBean, String currentCurrency, PrintStream out) {
        StringBuffer res = new StringBuffer();
        res.append("################" + "\n");
        res.append("# Cart Content #" + "\n");
        res.append("################" + "\n");

        DecimalFormat myFormatter = new DecimalFormat("##0.00");

        for (CartLine line : ecomCustomerBean.getProductsInCart()) {
            res.append("\tProduct #" + line.getStock().getProduct().getProductId() + "  | " +
                    line.getStock().getProduct().getProductName() +
                    "\t[store = #" + line.getStock().getStore() + "]" +
                    "\n\t\tPrice: " + myFormatter.format(ecomCustomerBean.convertFromEuro(line.getStock().getProductPrice(), currentCurrency)) + currentCurrency + "" +
                    "\t\tQuantity: " + line.getOrderedQuantity() + "\n");
        }
        res.append("\n\t\tTotal : " + myFormatter.format(ecomCustomerBean.convertFromEuro(ecomCustomerBean.getCartTotalPrice(), currentCurrency)) + currentCurrency);
        return res.toString();
    }

    /**
     * @brief Affichage du contenu du panier (XML)
     * @param ecomCustomerBean : bean remote client
     * @param currentCurrency : devise active
     * @param out : flux d'affichage std
     * @return les données à afficher selon le type de sortie positionné
     */
    public String printCartXML(EcomCustomerRemote ecomCustomerBean, String contextCurrency, PrintStream out) {
        Element cart = new Element("cart");
        org.jdom.Document document = new Document(cart);

        Element cartSate = new Element("state");
        cartSate.setText(String.valueOf(ecomCustomerBean.getCartState()));
        cart.addContent(cartSate);

        DecimalFormat myFormatter = new DecimalFormat("##0.00");

        for (CartLine line : ecomCustomerBean.getProductsInCart()) {

            ProductBean p = line.getStock().getProduct();
            ProductStoreBean s = line.getStock().getStore();

            Element product = ProductCommandImpl.buildXMLProductNode(p);
            Element store = StoreCommandImpl.buildXMLStoreNode(s, false, ecomCustomerBean, contextCurrency);
            product.addContent(store);
            cart.addContent(product);
            
            Element quantity = new Element("quantity");
            quantity.setText(String.valueOf(line.getOrderedQuantity()));
            product.addContent(quantity);

            Element price = new Element("price");
            price.setText(myFormatter.format(ecomCustomerBean.convertFromEuro(line.getStock().getProductPrice(), contextCurrency)));
            Attribute currency = new Attribute("currency", contextCurrency);
            price.setAttribute(currency);
            product.addContent(price);

        }

        Element totalAmount = new Element("total");
        totalAmount.setText(myFormatter.format(ecomCustomerBean.convertFromEuro(ecomCustomerBean.getCartTotalPrice(), contextCurrency)));
        Attribute currency = new Attribute("currency", contextCurrency);
        totalAmount.setAttribute(currency);

        cart.addContent(totalAmount);

        XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
        return sortie.outputString(document);
    }
}
